using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace VerticalProcesses
{
    public class Configuration
    {
        string gruInfoFile;
        string cduInfoFile;
        Dictionary<string, string> metFileNames = new Dictionary<string, string>();
        
        //options
        DateTime[] timeSpan = new DateTime[2];
        double timeStepHrs;
        string outputPath;
        bool gruOnly = false;
        string routing = "NULL";
        bool outputDates = false;
        string evapoEq = "NULL";
        string snowEngergyInputEq = "NULL";
        string soilType = "NULL";
        string snowpackType = "NULL";
        string canopyType = "NULL";

        //parameters
        Dictionary<string, double> gruGlobalParameters = new Dictionary<string, double>();
        Dictionary<string, double> cduGlobalParameters = new Dictionary<string, double>();
        DateTime[] outputThisDates;
        string[] gruoutputvars;
        string[] cduoutputvars;

        public Dictionary<string,string> Metfiles
        {
            get { return metFileNames; }
        }
        public string GRUInfoFile
        {
            get { return gruInfoFile; }
        }

        public string CDUInfoFile
        {
            get { return cduInfoFile; }
        }

        public string OutputPath
        {
            get { return outputPath; }
        }

        public DateTime[] TimeSpan
        {
            get { return timeSpan; }
        }

        public double TimeStepHrs
        {
            get { return timeStepHrs; }
        }
        public bool GruOnly
        {
            get { return gruOnly; }
        }
        public string Routing
        {
            get { return routing; }
        }
        public bool OutputDates
        {
            get { return outputDates; }
        }

        public string EvapoEq
        {
            get { return evapoEq; }
        }
        public string SnowEngergyInputEq
        {
            get { return snowEngergyInputEq; }
        }

        public string CanopyType
        {
            get { return canopyType; }
        }

        public string SnowpackType
        {
            get { return snowpackType; }
        }
        
        public string SoilType
        {
            get { return soilType; }
        }
        public Dictionary<string, double> GruGlobalParameters
        {
            get { return gruGlobalParameters; }
        }
        public Dictionary<string, double> CduGlobalParameters
        {
            get { return cduGlobalParameters; }
        }
        public DateTime[] OutputThisDates
        {
            get { return outputThisDates; }
        }
        public string[] GruOutputVars
        {
            get { return gruoutputvars; }
        }
        public string[] CduOutputVars
        {
            get { return cduoutputvars; }
        }
        
        public Configuration(string configFile)
        {
            
            //open,read and parse configfile
            StreamReader srConfig = new StreamReader(configFile);
            string contentConfig = srConfig.ReadToEnd();
            srConfig.Close();
            ParseConfigFile(contentConfig);
        }
            
        private void ParseConfigFile(string contentConfig)
        {
            //split configfile into blocks
            string filepaths = Regex.Match(contentConfig, @"\[FILEPATHS\].*(?=\[MODELOPTIONS\])", RegexOptions.Singleline).ToString();
            string modeloptions = Regex.Match(contentConfig, @"\[MODELOPTIONS\].*(?=\[GRUPARAMETERS\])", RegexOptions.Singleline).ToString();
            string gruparameters = Regex.Match(contentConfig, @"\[GRUPARAMETERS\].*(?=\[CDUPARAMETERS\])", RegexOptions.Singleline).ToString();
            string cduparameters = Regex.Match(contentConfig, @"\[CDUPARAMETERS\].*(?=\[OUTPUTVARIABLES\])", RegexOptions.Singleline).ToString();
            string outputvars = Regex.Match(contentConfig, @"\[OUTPUTVARIABLES\].*(?=\[OUTPUTDATES\])", RegexOptions.Singleline).ToString();
            string outputdates = Regex.Match(contentConfig, @"\[OUTPUTDATES\].*", RegexOptions.Singleline).ToString();
            
            Regex filepathsreg = new Regex("(?<Keyword>\\w+)\\s*=\\s*\"(?<Value>\\S*)\"");
            MatchCollection filepathentries = filepathsreg.Matches(filepaths);
            Regex modeloptionsreg = new Regex(@"(?<Keyword>\w+)\s*=\s*(?<Value>\w+)");
            MatchCollection modeloptionsentries = modeloptionsreg.Matches(modeloptions);
            Regex startdatereg = new Regex(@"(?<Keyword>\w+)\s*=\s*(?<Value>\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}:\d{2})");
            MatchCollection startdatentry = startdatereg.Matches(modeloptions); 
            Regex gruparametersreg = new Regex(@"(?<Keyword>\w+)\s*=\s*(?<Value>\w*.\d*)");
            MatchCollection gruparametersentries = gruparametersreg.Matches(gruparameters);
            Regex cduparametersreg = new Regex(@"(?<Keyword>\w+)\s*=\s*(?<Value>\w*.\d*)");
            MatchCollection cduparametersentries = cduparametersreg.Matches(cduparameters);          
            Regex gruoutputvarsreg = new Regex("(?<Name>(?<=gru:\\s*\")\\w+)");
            MatchCollection gruoutputvarsentries = gruoutputvarsreg.Matches(outputvars);
            Regex cduoutputvarsreg = new Regex("(?<Name>(?<=cdu:\\s*\")\\w+)");            
            MatchCollection cduoutputvarsentries = cduoutputvarsreg.Matches(outputvars);                        
            Regex outputdatesreg = new Regex(@"(?<Keyword>\w+)\s*=\s*(?<Value>\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}:\d{2})");
            MatchCollection outputdatesentries = outputdatesreg.Matches(outputdates);


            
            foreach (Match entry in filepathentries)
            {
                switch (entry.Groups["Keyword"].Value.ToLower())                       
                {
                    case "gruinfofile": gruInfoFile = entry.Groups["Value"].Value; break;
                    case "cduinfofile": cduInfoFile = entry.Groups["Value"].Value; break;
                    case "outputpath": outputPath = entry.Groups["Value"].Value; break;
                    default:
                        metFileNames.Add(entry.Groups["Keyword"].Value.ToLower(), entry.Groups["Value"].Value); 
                        break;
                }
            }
           
            timeSpan[0] = Convert.ToDateTime(startdatentry[0].Groups["Value"].ToString());
            timeSpan[1] = Convert.ToDateTime(startdatentry[1].Groups["Value"].ToString());

            foreach (Match entry in modeloptionsentries)
            {
                switch (entry.Groups["Keyword"].Value.ToLower())
                {
                    case "timestephours": timeStepHrs = Convert.ToDouble(entry.Groups["Value"].Value); break;
                    case "gruonly": gruOnly = Convert.ToBoolean(entry.Groups["Value"].Value); break;
                    case "outputdates": outputDates = Convert.ToBoolean(entry.Groups["Value"].Value); break;
                    case "routing": routing = Convert.ToString(entry.Groups["Value"].Value); break;
                    case "evaporationeq": evapoEq = Convert.ToString(entry.Groups["Value"].Value); break;
                    case "snowmelteq": snowEngergyInputEq = Convert.ToString(entry.Groups["Value"].Value); break;
                    case "canopytype": canopyType = Convert.ToString(entry.Groups["Value"].Value); break;
                    case "snowpacktype": snowpackType = Convert.ToString(entry.Groups["Value"].Value); break;
                    case "soiltype": soilType = Convert.ToString(entry.Groups["Value"].Value); break;
                }
            }


            foreach (Match entry in gruparametersentries)
            {
                switch (entry.Groups["Keyword"].Value.ToLower())
                {
                    case "tt": gruGlobalParameters.Add("tt", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "tti": gruGlobalParameters.Add("tti", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "af": gruGlobalParameters.Add("af", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "bf": gruGlobalParameters.Add("bf", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "cf": gruGlobalParameters.Add("cf", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "ccrf": gruGlobalParameters.Add("ccrf", Convert.ToDouble(entry.Groups["Value"].Value)); break;                    
                    case "t0": gruGlobalParameters.Add("t0", Convert.ToDouble(entry.Groups["Value"].Value)); break;                    
                    case "whc": gruGlobalParameters.Add("whc", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "maxswesurf": gruGlobalParameters.Add("maxswesurf", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "threshrs": gruGlobalParameters.Add("threshrs", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "maxsnowint": gruGlobalParameters.Add("maxsnowint", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "crintf": gruGlobalParameters.Add("crintf", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "csintf": gruGlobalParameters.Add("csintf", Convert.ToDouble(entry.Groups["Value"].Value)); break;                   
                    case "maxrainint": gruGlobalParameters.Add("maxrainint", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "alphac": gruGlobalParameters.Add("alphac", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "fc": gruGlobalParameters.Add("fc", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "beta": gruGlobalParameters.Add("beta", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "lp": gruGlobalParameters.Add("lp", Convert.ToDouble(entry.Groups["Value"].Value)); break;            
                }

            }
            foreach (Match entry in cduparametersentries)
            {
                switch (entry.Groups["Keyword"].Value.ToLower())
                {
                    case "fracperc": cduGlobalParameters.Add("fracperc", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "kf": cduGlobalParameters.Add("kf", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "alpha": cduGlobalParameters.Add("alpha", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                    case "ks": cduGlobalParameters.Add("ks", Convert.ToDouble(entry.Groups["Value"].Value)); break;
                }
            }


            gruoutputvars = new string[gruoutputvarsentries.Count];

            for (int i = 0; i < gruoutputvars.Length; i++)
            {
                gruoutputvars[i] = (gruoutputvarsentries[i].Groups["Name"].Value);
            }

            cduoutputvars = new string[cduoutputvarsentries.Count];
            for (int i = 0; i < cduoutputvars.Length; i++)
            {

                cduoutputvars[i] = (cduoutputvarsentries[i].Groups["Name"].Value);
            
            }

            outputThisDates = new DateTime[outputdatesentries.Count];
            
            for(int i=0;i < outputThisDates.Length;i++)
            {
              outputThisDates[i]=Convert.ToDateTime(outputdatesentries[i].Groups["Value"].ToString());
                      
            }           
        }
    }
}
